package org.mysterylab.utopiaframework.commons.security.springsecurity3.util;

import java.util.Collection;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

/**
 * Spring Security 的工具类, 注意支持 3.0.x 以上版本.
 * 
 * @author zhouych
 */
public class SpringSecurityUtil {

	/**
	 * 获取当前登录的用户, 返回值为 {@link User} 类及其子类, 如果当前未有登录用户则返回 null.
	 * 
	 * @param <T>
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T extends User> T getCurrentUser() {
		
		Authentication authentication = getAuthentication();
		if (authentication == null) {
			return null;
		}
		Object principal = authentication.getPrincipal();
		if (!(principal instanceof User)) {
			return null;
		}
		
		return (T) principal;
	}
	
	/**
	 * 取得当前登录用户的登录名, 如果当前未有登录用户则返回空字符串.
	 * 
	 * @return
	 */
	public static String getCurrentUserName() {
		
		Authentication authentication = getAuthentication();
		if (authentication == null || authentication.getPrincipal() == null) {
			return "";
		}
		return authentication.getName();
	}
	
	/**
	 * 取得当前登录用户的 IP 地址, 如果当前未有登录用户则返回空字符串.
	 * 
	 * @return
	 */
	public static String getCurrentUserIp() {
		
		Authentication authentication = getAuthentication();
		if (authentication == null) {
			return "";
		}
		Object details = authentication.getDetails();
		if (!(details instanceof WebAuthenticationDetails)) {
			return "";
		}
		
		return ((WebAuthenticationDetails) details).getRemoteAddress();
	}
	
	/**
	 * 判断用户是否拥有角色, 如果用户拥有参数中的任意一个角色则返回 true, 否则返回 false.
	 * 
	 * @param roles
	 * @return
	 */
	public static boolean hasAnyRole(String... roles) {
		
		Authentication authentication = getAuthentication();
		if (authentication == null) {
			return false;
		}
		Collection<GrantedAuthority> authorities = authentication.getAuthorities();
		for (String role : roles) {
			for (GrantedAuthority authority : authorities) {
				if (role.equals(authority.getAuthority())) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 将 {@link UserDetails} 保存到 Security Context. 该方法可作为今后与 SSO
	 * 等其他认证方案进行集成的重要接口.
	 * 
	 * @param userDetails
	 *            已初始化好的用户信息
	 * @param request
	 *            用于获取用户 IP 地址信息, 可为 null
	 */
	public static void saveUserDetailsToContext(UserDetails userDetails,
			HttpServletRequest request) {
		
		PreAuthenticatedAuthenticationToken authenticationToken =
			new PreAuthenticatedAuthenticationToken(userDetails,
					userDetails.getPassword(), userDetails.getAuthorities());
		
		if (request != null) {
			authenticationToken.setDetails(new WebAuthenticationDetails(request));
		}
		
		SecurityContextHolder.getContext().setAuthentication(authenticationToken);
	}
	
	/**
	 * 取得 {@link Authentication}, 如果当前的 {@link SecurityContext} 为空则返回 null.
	 * 
	 * @return
	 */
	private static Authentication getAuthentication() {
		
		SecurityContext context = SecurityContextHolder.getContext();
		if (context == null) {
			return null;
		}
		return context.getAuthentication();
	}
}
